//
//  MD5Handler.m
//  iOS_MD5
//
//  Created by Scott on 16/2/5.
//  Copyright © 2016年 Scott. All rights reserved.
//

#import "MD5Handler.h"
#import <CommonCrypto/CommonCrypto.h>


@implementation MD5Handler

#pragma mark - 知识点1 对字符串进行MD5计算.
/** 
 * MD5以512位分组来处理输入的信息，且每一分组又被划分为16个32位子分组，经过了一系列的处理后，算法的输出由四个32位分组组成，将这四个32位分组级联后将生成一个128位散列值.
 * 所以获取MD5值的数据在内存中是必须连续存放的, 而对象类型数据在内存中不是连续存放的, 所以要将字符串对象转化为C字符串, 这样在内存中就是连续存放的, 然后进行MD5计算.
 */
+ (NSString *)stringFromMD5:(NSString *)sourceString {
    
    // 1. 转化为C字符串.
    const char *string = sourceString.UTF8String;

    
    // 2. 创建字符串数组接收MD5值.
    unsigned char bytes[CC_MD5_DIGEST_LENGTH];
    
    // 3. 通过库函数进行MD5计算.
    /**
     * @param data 进行MD5计算的数据首地址(指针).
     * @param len 要处理数据的长度.
     * @param md 存储128位散列值的内存首地址(指针).
     */
     extern unsigned char * CC_MD5(const void *data, CC_LONG len, unsigned char *md);
    
    CC_MD5(string, (CC_LONG)strlen(string), bytes);
    
    // 4. 创建字符串对象存储MD5值
    NSMutableString *md5Str = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
    
    for (NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++) {
        [md5Str appendFormat:@"%02x", bytes[count]];
    }
    
    
    return md5Str;
}




#pragma mark - 知识点2 对其它对象进行MD5计算.
/** 对其它对象获取MD5. 
 * MD5原理是对数据进行512位为单位进行拆分, 因此要进行处理的数据要在内存中连续存在, NSString类有相关的API(UTF8String, cStringUsingEncoding:)能将字符串对象转化为c字符串(在内存中是连续的), 而其它对象没有相关的API可以转化为在内存中连续的保存实现(多是嵌套指针的形式.) . 而NSData的作用可以将对象转化为在内存中连续存储(因此,NSData有个概念就是最大的数据限制(8EB)). 所以对文件进行MD5计算时, 首先转化为NSData对象(在内存中连续存储), 然后对这段连续的内存内容进行MD5计算.
 */
+ (NSString *)objectFromMD5:(NSString *)path {

    // 1. 根据文件路径获取NSData对象.
    NSData *data = [NSData dataWithContentsOfFile:path];
    
    // 2. 创建MD5结构体变量.
    CC_MD5_CTX md5;
    
    // 3. 初始化
    CC_MD5_Init(&md5);
    
    // 4. 准备MD5计算.
    CC_MD5_Update(&md5, data.bytes, (CC_LONG)data.length);
    
    // 5. 创建字符数组.
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    
    // 6. 结束MD5计算
    CC_MD5_Final(result, &md5);
    
    // 7. 创建字符串对象存储MD5值.
    NSMutableString *md5Stri = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
    
    for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [md5Stri appendFormat:@"%02X", result[i]];
    }
    
    return md5Stri;
}

@end
